package com.netease.demo.shortvideo.activity;

import android.app.Activity;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.text.InputType;
import android.text.TextUtils;
import android.util.SparseArray;
import android.view.MotionEvent;
import android.view.SurfaceView;
import android.view.View;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.RadioButton;
import android.widget.RadioGroup;
import android.widget.RelativeLayout;
import android.widget.SeekBar;
import android.widget.TextView;
import android.widget.Toast;

import com.bumptech.glide.Glide;
import com.netease.LSMediaFilter.filter.helper.MagicFilterType;
import com.netease.LSMediaFilter.view.CameraSurfaceView;
import com.netease.demo.shortvideo.R;
import com.netease.demo.shortvideo.constant.ResolutionType;
import com.netease.demo.shortvideo.model.VideoCaptureParams;
import com.netease.demo.shortvideo.model.VideoItem;
import com.netease.demo.shortvideo.shortvideo.MediaCaptureController;
import com.netease.demo.shortvideo.shortvideo.model.MediaCaptureOptions;
import com.netease.demo.shortvideo.shortvideo.videoprocess.VideoProcessController;
import com.netease.demo.shortvideo.shortvideo.videoprocess.model.VideoProcessOptions;
import com.netease.demo.shortvideo.widget.CircleProgressView;
import com.netease.nim.uikit.common.activity.UI;
import com.netease.nim.uikit.common.ui.dialog.EasyAlertDialog;
import com.netease.nim.uikit.common.ui.dialog.EasyAlertDialogHelper;
import com.netease.nim.uikit.common.ui.dialog.EasyEditDialog;
import com.netease.nim.uikit.common.util.file.FileUtil;
import com.netease.nim.uikit.common.util.storage.StorageType;
import com.netease.nim.uikit.common.util.storage.StorageUtil;
import com.netease.nim.uikit.common.util.sys.TimeUtil;
import com.netease.transcoding.TranscodingAPI;

import java.io.File;
import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;

/**
 * 视频录制界面
 * Created by hzxuwen on 2017/4/6.
 */

public class VideoShootActivity extends UI implements MediaCaptureController.MediaCaptureControllerCallback,
        View.OnClickListener, VideoProcessController.VideoProcessCallback {
    // constant
    private static final int DEFAULT_VIDEO_COUNTS = 3;
    private static final long DEFAULT_VIDEO_TIME = 10 * 1000;
    public static final String EXTRA_VIDEO_ITEM = "video_item";
    public static final int REQUEST_CODE = 1000;
    // view
    private CameraSurfaceView videoView;
    private RelativeLayout startLayout; // 开始录制布局
    private RelativeLayout recodingLayout; // 正在录制布局
    private TextView startRecodingBtn;
    private SeekBar seekBar; // 变焦控制
    private RelativeLayout paramLayout; // 录制参数layout
    private RelativeLayout paramSelectionLayout; // 参数选择layout
    private RelativeLayout paramWrapperLayout; // 参数选择layout的底部透明层，用于点击空白处消失
    private RadioGroup clarityRadioGroup; // 清晰度按钮选择
    private RadioGroup countsRadioGroup; // 分段数按钮选择
    private RadioGroup timeRadioGroup; // 总时长按钮选择
    private TextView modeText; // 清晰度显示
    private TextView timeText; // 时间显示
    private TextView countsText; // 分段数显示
    private ImageView takeCountsImage; // 分段数显示进度条
    private CircleProgressView circleProgressView; // 录制时间进度条
    private RelativeLayout combinationLayout; // 拼接等待界面
    private ImageView loadingImage; // 拼接等待图片
    private CircleProgressView loadingView; // 拼接loading
    /**
     * 录制相关按钮
     */
    private TextView previousBtn; // 上一步按钮
    private TextView finishBtn; // 完成按钮
    private TextView cancelBtn; // 取消按钮
    /**
     * 顶部控制条
     */
    private ImageButton filterBtn; // 滤镜按钮
    private ImageButton cameraSwitchBtn; // 摄像头转换按钮
    private RadioGroup filterGroup; // 滤镜按钮
    private RelativeLayout filterLayout; // 滤镜布局

    // data
    private MediaCaptureController mediaCaptureController; // 录制视频控制器
    private VideoProcessController videoProcessController; // 视频编辑控制器
    private MediaCaptureOptions mediaCaptureOptions; // 视频录制参数配置
    private VideoCaptureParams videoCaptureParams; // 录制视频的参数（界面显示，用户操作配置的），分几段，时间等
    private int currentCount = 0; // 当前录制哪段视频
    private List<String> videoPathList = new ArrayList<>(); // 录制的分段视频地址
    private String outputPath; // 拼接后的视频地址
    private VideoItem videoItem; // 拼接后的video
    private String displayName; // 视频名称
    private SparseArray<MagicFilterType> filterArray;
    private float time; // 录制计时
    private Timer timer;
    private TimerTask timerTask;

    public static void startActivityForResult(Context context) {
        Intent intent = new Intent();
        intent.setClass(context, VideoShootActivity.class);
        ((Activity) context).startActivityForResult(intent, REQUEST_CODE);
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.video_shoot_activity);

        findViews();
        setListener();
        initVideoParams();
        initData();
        initMediaCapture();
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        if (mediaCaptureController != null) {
            mediaCaptureController.release();
            mediaCaptureController = null;
            mediaCaptureOptions = null;
        }
        getHandler().removeCallbacksAndMessages(null);
        stopCounting();
    }

    private void findViews() {
        videoView = findView(R.id.camerasurfaceview);
        startLayout = findView(R.id.start_layout);
        recodingLayout = findView(R.id.recording_layout);
        startRecodingBtn = findView(R.id.start_recoding_btn);
        seekBar = findView(R.id.seekbar);
        paramLayout = findView(R.id.param_layout);
        paramSelectionLayout = findView(R.id.param_selection_layout);
        paramWrapperLayout = findView(R.id.param_wrapper_layout);
        clarityRadioGroup = findView(R.id.clarity_radio_group);
        countsRadioGroup = findView(R.id.counts_radio_group);
        timeRadioGroup = findView(R.id.time_radio_group);
        modeText = findView(R.id.mode);
        timeText = findView(R.id.time);
        countsText = findView(R.id.counts);
        takeCountsImage = findView(R.id.take_counts_image);
        circleProgressView = findView(R.id.progress_view);
        // 顶部控制条按钮
        filterBtn = findView(R.id.filter_btn);
        cameraSwitchBtn = findView(R.id.switch_btn);
        filterGroup = findView(R.id.filter_group);
        filterLayout = findView(R.id.filter_layout);
        // 录制相关按钮
        previousBtn = findView(R.id.previous_btn);
        finishBtn = findView(R.id.finish_btn);
        cancelBtn = findView(R.id.cancel_btn);
        // 拼接等待界面
        combinationLayout = findView(R.id.combination_layout);
        loadingImage = findView(R.id.loading_image);
        loadingView = findView(R.id.loading_view);
    }

    private void setListener() {
        startRecodingBtn.setOnClickListener(this);
        paramLayout.setOnClickListener(this);
        paramWrapperLayout.setOnClickListener(this);
        clarityRadioGroup.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() {
            @Override
            public void onCheckedChanged(RadioGroup radioGroup, int i) {
                int resId = radioGroup.getCheckedRadioButtonId();
                RadioButton button = findView(resId);
                if (button.getText().equals(getString(R.string.hd))) {
                    videoCaptureParams.setResolutionType(ResolutionType.HD);
                } else {
                    videoCaptureParams.setResolutionType(ResolutionType.FLUENT);
                }
            }
        });
        countsRadioGroup.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() {
            @Override
            public void onCheckedChanged(RadioGroup radioGroup, int i) {
                int resId = radioGroup.getCheckedRadioButtonId();
                RadioButton button = findView(resId);
                if (button.getText().equals(getString(R.string.one_count))) {
                    videoCaptureParams.setCount(1);
                } else if (button.getText().equals(getString(R.string.two_count))) {
                    videoCaptureParams.setCount(2);
                } else {
                    videoCaptureParams.setCount(3);
                }
            }
        });
        timeRadioGroup.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() {
            @Override
            public void onCheckedChanged(RadioGroup radioGroup, int i) {
                int resId = radioGroup.getCheckedRadioButtonId();
                RadioButton button = findView(resId);
                if (button.getText().equals(getString(R.string.first_time))) {
                    videoCaptureParams.setTime(6 * 1000);
                } else if (button.getText().equals(getString(R.string.second_time))) {
                    videoCaptureParams.setTime(10 * 1000);
                } else {
                    videoCaptureParams.setTime(30 * 1000);
                }
            }
        });
        // 顶部控制条
        filterBtn.setOnClickListener(this);
        cameraSwitchBtn.setOnClickListener(this);
        filterLayout.setOnClickListener(this);
        filterGroup.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() {
            @Override
            public void onCheckedChanged(RadioGroup radioGroup, int i) {
                int resId = radioGroup.getCheckedRadioButtonId();
                if (mediaCaptureController != null) {
                    mediaCaptureController.setFilterType(filterArray.get(resId));
                }
            }
        });
        // 录制相关按钮
        previousBtn.setOnClickListener(this);
        finishBtn.setOnClickListener(this);
        cancelBtn.setOnClickListener(this);
    }

    private void initVideoParams() {
        videoCaptureParams = new VideoCaptureParams(DEFAULT_VIDEO_COUNTS, DEFAULT_VIDEO_TIME, ResolutionType.HD);
    }

    private void initData() {
        videoProcessController = new VideoProcessController(this, this);
        filterArray = new SparseArray<>();
        filterArray.put(R.id.no_filter_btn, MagicFilterType.NONE);
        filterArray.put(R.id.filter_a_btn, MagicFilterType.PIXAR);
        filterArray.put(R.id.filter_b_btn, MagicFilterType.FAIRYTALE);
        filterArray.put(R.id.filter_c_btn, MagicFilterType.CALM);
        filterArray.put(R.id.filter_d_btn, MagicFilterType.BROOKLYN);
    }

    private void initMediaCapture() {
        mediaCaptureOptions = new MediaCaptureOptions();
        mediaCaptureOptions.mFilePath = StorageUtil.getWritePath(System.currentTimeMillis() + ".mp4", StorageType.TYPE_VIDEO);
        videoPathList.add(mediaCaptureOptions.mFilePath);
        setResolution(mediaCaptureOptions);
        mediaCaptureController = new MediaCaptureController(this, this, mediaCaptureOptions);
    }

    private void setResolution(MediaCaptureOptions options) {
        if (videoCaptureParams.getResolutionType() == ResolutionType.HD) {
            options.mVideoPreviewWidth = 1280;
            options.mVideoPreviewHeight = 720;
        } else if (videoCaptureParams.getResolutionType() == ResolutionType.SD) {
            options.mVideoPreviewWidth = 640;
            options.mVideoPreviewHeight = 320;
        } else {
            options.mVideoPreviewWidth = 320;
            options.mVideoPreviewHeight = 240;
        }
    }

    /*************************
     * MediaCaptureControllerCallback
     **************************/

    @Override
    public void onPreviewInited() {
        videoView.setVisibility(View.VISIBLE);
        startRecodingBtn.setVisibility(View.VISIBLE);
    }

    @Override
    public void setPreviewSize(int videoPreviewWidth, int videoPreviewHeight) {
        videoView.setPreviewSize(videoPreviewWidth, videoPreviewHeight);
    }

    @Override
    public SurfaceView getSurfaceView() {
        return videoView;
    }

    @Override
    public void onRelease() {
        videoView.setVisibility(View.GONE);
        mediaCaptureController = null;
        if (currentCount == videoCaptureParams.getCount()) {
            // 最后一段视频录制完成, 跳转到完成录制界面
            Toast.makeText(this, "done!", Toast.LENGTH_SHORT).show();
            currentCount = 0;
            showNameDialog();
        } else {
            // 不是最后一段视频录制完成，重新初始化，显示preview预览画面
            mediaCaptureOptions = null;
            initMediaCapture();
            updateStopRecodingUI();
        }
    }

    /*************************
     * MediaCaptureControllerCallback end
     **************************/

    @Override
    public void onClick(View view) {
        switch (view.getId()) {
            case R.id.start_recoding_btn:
                paramLayout.setVisibility(View.GONE);
                startRecording();
                break;
            case R.id.param_layout:
                showParamSelectionLayout(true);
                break;
            case R.id.param_wrapper_layout:
                // 重新初始化
                mediaCaptureController.release();
                videoPathList.clear();
                updateParamLayout();
                showParamSelectionLayout(false);
                break;
            case R.id.filter_btn:
                filterLayout.setVisibility(View.VISIBLE);
                break;
            case R.id.switch_btn:
                break;
            case R.id.filter_layout:
                filterLayout.setVisibility(filterGroup.getVisibility() == View.VISIBLE ? View.GONE : View.VISIBLE);
                break;
            case R.id.previous_btn:
                deletePreviousVideo();
                break;
            case R.id.finish_btn:
                if (videoPathList.size() > 0) {
                    videoPathList.remove(videoPathList.size() - 1);
                }
                showNameDialog();
                break;
            case R.id.cancel_btn:
                if (videoPathList.size() > 0) {
                    videoPathList.remove(videoPathList.size() - 1);
                }
                if (currentCount > 0) {
                    currentCount--;
                }
                stopCounting();
                getHandler().removeCallbacks(stopRecodingRunnable);
                mediaCaptureController.release();
                break;
        }
    }

    private void startRecording() {
        mediaCaptureController.startRecording();
        updateStartRecordingUI();
        getHandler().postDelayed(stopRecodingRunnable, videoCaptureParams.getTime() / videoCaptureParams.getCount());
        currentCount++;
    }

    private void showParamSelectionLayout(boolean isShow) {
        paramWrapperLayout.setVisibility(isShow ? View.VISIBLE : View.GONE);
    }

    // 更新参数显示
    private void updateParamLayout() {
        if (videoCaptureParams.getResolutionType().equals(ResolutionType.HD)) {
            modeText.setText(R.string.hd);
        } else if (videoCaptureParams.getResolutionType().equals(ResolutionType.SD)) {
            modeText.setText(R.string.sd);
        } else {
            modeText.setText(R.string.fluent);
        }
        timeText.setText(String.format(getString(R.string.param_time), videoCaptureParams.getTime() / 1000));
        countsText.setText(String.format(getString(R.string.param_count), videoCaptureParams.getCount()));
        // 分段数进度条
        takeCountsImage.setBackgroundResource(0);
        if (videoCaptureParams.getCount() == 1) {
            takeCountsImage.setImageResource(R.drawable.ic_one_take);
        } else if (videoCaptureParams.getCount() == 2) {
            takeCountsImage.setImageResource(R.drawable.ic_two_take);
        } else {
            takeCountsImage.setImageResource(R.drawable.ic_three_take);
        }
    }

    private Runnable stopRecodingRunnable = new Runnable() {
        @Override
        public void run() {
            mediaCaptureController.release();
            stopCounting();
        }
    };

    // 停止计时器
    private void stopCounting() {
        if (timer != null) {
            timer.cancel();
            timer = null;
        }
        if (timerTask != null) {
            timerTask.cancel();
            timerTask = null;
        }
    }

    // 更新录制间，界面展示
    private void updateStopRecodingUI() {
        startLayout.setVisibility(View.VISIBLE);
        recodingLayout.setVisibility(View.GONE);
        startRecodingBtn.setText(currentCount == 0 ? R.string.start_recoding : R.string.continue_recoding);
        previousBtn.setVisibility(currentCount != 0 ? View.VISIBLE : View.GONE);
        finishBtn.setVisibility(currentCount != 0 ? View.VISIBLE : View.GONE);

        if (currentCount == 0) {
            paramLayout.setVisibility(View.VISIBLE);
        }

        // 拍摄了几段视频的显示
        takeCountsImage.setVisibility(View.VISIBLE);
        takeCountsImage.setBackgroundResource(0);
        if (videoCaptureParams.getCount() == 2) {
            takeCountsImage.setImageResource(currentCount == 1 ? R.drawable.ic_take_two_one : R.drawable.ic_two_take);
        } else if (videoCaptureParams.getCount() == 3) {
            if (currentCount == 0) {
                takeCountsImage.setImageResource(R.drawable.ic_three_take);
            } else if (currentCount == 1) {
                takeCountsImage.setImageResource(R.drawable.ic_take_three_one);
            } else if (currentCount == 2) {
                takeCountsImage.setImageResource(R.drawable.ic_take_three_two);
            }
        }
    }

    // 更新开始录制界面展示
    private void updateStartRecordingUI() {
        startLayout.setVisibility(View.GONE);
        recodingLayout.setVisibility(View.VISIBLE);
        takeCountsImage.setVisibility(View.GONE);
        circleProgressView.setFormat("");
        circleProgressView.setMaxProgress(videoCaptureParams.getTime() / videoCaptureParams.getCount() / 1000);
        time = 0;
        timer = new Timer();
        timerTask = new TimerTask() {
            @Override
            public void run() {
                getHandler().post(new Runnable() {
                    @Override
                    public void run() {
                        time += 0.1;
                        float temp = (float) (Math.round(time * 10)) / 10;
                        if (temp > videoCaptureParams.getTime() / videoCaptureParams.getCount() / 1000) {
                            return;
                        }
                        circleProgressView.setProgress(temp);
                        circleProgressView.setContent(String.valueOf(temp));
                    }
                });
            }
        };
        timer.schedule(timerTask, 1, 100);
    }

    // 删除上一分段视频
    private void deletePreviousVideo() {
        if (currentCount > 0) {
            currentCount--;
        }
        if (videoPathList.size() > 1) {
            // 上一步操作, 删除刚刚录制的文件
            FileUtil.deleteFile(videoPathList.get(videoPathList.size() - 2));
            videoPathList.remove(videoPathList.size() - 2);
        }
        updateStopRecodingUI();
    }


    /******************************
     * 视频拼接
     ********************************/

    // 设置视频名称
    private void showNameDialog() {
        final EasyEditDialog requestDialog = new EasyEditDialog(VideoShootActivity.this);
        requestDialog.setEditTextMaxLength(200);
        requestDialog.setTitle(getString(R.string.video_name));
        requestDialog.setEditHint("新视频" + TimeUtil.getMonthTimeString(System.currentTimeMillis()));
        requestDialog.setInputType(InputType.TYPE_CLASS_TEXT);
        requestDialog.setCustomTextWatcher(true);
        requestDialog.addNegativeButtonListener(R.string.cancel, new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                requestDialog.dismiss();
                showVideoDoneToast();
            }
        });
        requestDialog.addPositiveButtonListener(R.string.save, new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                displayName = requestDialog.getEditMessage();
                if (TextUtils.isEmpty(displayName)) {
                    Toast.makeText(VideoShootActivity.this, "不能为空", Toast.LENGTH_SHORT).show();
                    return;
                }
                requestDialog.dismiss();
                startSnapshot(getThumbPath());
            }
        });
        requestDialog.setOnCancelListener(new DialogInterface.OnCancelListener() {
            @Override
            public void onCancel(DialogInterface dialog) {
            }
        });
        requestDialog.show();
    }

    // 显示拍摄已完成
    private void showVideoDoneToast() {
        EasyAlertDialogHelper.OnDialogActionListener listener = new EasyAlertDialogHelper.OnDialogActionListener() {

            @Override
            public void doCancelAction() {
                deletePreviousVideo();
            }

            @Override
            public void doOkAction() {
                showNameDialog();
            }
        };

        final EasyAlertDialog dialog = EasyAlertDialogHelper.createOkCancelDiolag(this, null, getString(R.string.take_video_done),
                getString(R.string.next_step), getString(R.string.delete_pre_video), false, listener);
        dialog.show();
    }

    // 生成视频缩略图
    private void startSnapshot(String path) {
        TranscodingAPI.SnapshotPara para = new TranscodingAPI.SnapshotPara();
        try {
            para.setInputFile(videoPathList.get(0));
            para.setOffset(1);
            para.setInterval(0);
            para.setPicWidth(240);
            para.setPicHeight(320);
            para.setOutputFile(path);
        } catch (Exception e) {
            e.printStackTrace();
            return;
        }
        videoProcessController.startSnapShot(para);
    }

    @NonNull
    private String getThumbPath() {
        String path = StorageUtil.getWritePath(displayName + ".jpg", StorageType.TYPE_THUMB_IMAGE);
        File file = new File(path);
        if (!file.exists()) {
            try {
                //在指定的文件夹中创建文件
                file.createNewFile();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return path;
    }

    // 开始拼接
    private void startCombination() {
        VideoProcessOptions videoProcessOptions;
        try {
            videoProcessOptions = new VideoProcessOptions(mediaCaptureOptions);
            // 设置待拼接的文件
            TranscodingAPI.InputFilePara inputFilePara = videoProcessOptions.getInputFilePara();
            String[] arr = new String[videoPathList.size()];
            arr = videoPathList.toArray(arr);
            inputFilePara.setInputMainFileArray(arr);
            videoProcessOptions.setInputFilePara(inputFilePara);
            // 设置拼接后文件存储地址
            outputPath = StorageUtil.getWritePath(displayName + ".mp4", StorageType.TYPE_VIDEO);
            TranscodingAPI.OutputFilePara outputFilePara = videoProcessOptions.getOutputFilePara();
            outputFilePara.setOutputFile(outputPath);
            videoProcessOptions.setOutputFilePara(outputFilePara);
        } catch (Exception e) {
            e.printStackTrace();
            return;
        }
        // videoItem
        videoItem = new VideoItem();
        videoItem.setFilePath(outputPath);
        videoItem.setDisplayName(displayName);
        videoItem.setDateTaken(TimeUtil.getNowDatetime());
        String path = getThumbPath();
        videoItem.setUriString(path);

        // 开始拼接
        videoProcessController.startCombination(videoProcessOptions);
    }

    /**
     * ************************* VideoProcessCallback ************************
     */

    @Override
    public void onVideoProcessSuccess() {
        Toast.makeText(this, "保存成功！", Toast.LENGTH_SHORT).show();
        getHandler().postDelayed(new Runnable() {
            @Override
            public void run() {
                Intent intent = new Intent();
                intent.putExtra(EXTRA_VIDEO_ITEM, videoItem);
                setResult(Activity.RESULT_OK, intent);
                finish();
            }
        }, 3000);
    }

    @Override
    public void onVideoProcessFailed(int code) {

    }

    @Override
    public void onVideoSnapshotSuccess() {
        combinationLayout.setVisibility(View.VISIBLE);
        Glide.with(this).load(videoPathList.get(0)).into(loadingImage);
        loadingView.setFormat("%");
        loadingView.setMaxProgress(3);
        loadingView.setProgress(0);
        loadingView.setContent("0");
        startCombination();
    }

    @Override
    public void onVideoProcessUpdate(int process) {
        loadingView.setProgress(process);
        NumberFormat numberFormat = NumberFormat.getInstance();

        // 设置精确到小数点后0位
        numberFormat.setMaximumFractionDigits(0);

        String result = numberFormat.format((float) process / (float) 3 * 100);
        loadingView.setContent(result);
    }

    /**
     * ************************* VideoProcessCallback  end ************************
     */

    /**
     * ************ 变焦 ************
     */
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                if (mediaCaptureController != null) {
                    mediaCaptureController.setCameraFocus(event);
                }
                break;
            case MotionEvent.ACTION_MOVE:
                if (mediaCaptureController != null) {
                    mediaCaptureController.setCameraZoomParam(event);
                }
                break;
            case MotionEvent.ACTION_UP:
                break;
            default:
                break;
        }
        return true;
    }
}
